﻿#include "stdafx.h"
#ifdef LK_RANDOM_
namespace LK
{

	Random::Random() :arr(new LK::Collection::DefaultArray<u64>(5))
	{
		u64 *p = GetArray();
		GetArray()->LastElement() = 0;
		u8* pm = (u8*)(p + 3);
		pm[0] = ((u64)Time::GetLocal()) % 62 + 1;
		for (size_t i = 1; i < 3; ++i)
		{
			p[i + 1] = (p[i] << 1) | ((s64)p[i] < 0);
			pm[i] = (Rand() % 62) + 1;
			if (pm[i] == pm[i - 1])if (++pm[i] > 63)pm[i] = 1;
		}
		p[4] = 0;
	}
	Random& Random::operator= (const Random& v)
	{
		if (v.arr==null)return*this;
		if (v.GetArray()->size() > GetArray()->size())GetArray()->Resize(v.GetArray()->size());
		u64*p1 = GetArray();
		const u64*p2 = v.GetArray();
		for (index_t i = 0; i < v.GetArray()->size(); ++i)*p1++ = *p2++;
		return *this;
	}
	Random::Random(Random const &vr) :arr(cast<ptr<ICloneables>>(vr.arr)->Clone()) {}
	void Random::SwapWith(Random& x)
	{
		if (arr==null) { x.GetArray()->ResetTo(0); return; }
		Object::Swap(arr, x.arr);
		if (arr==null)arr = cast<ptr<ICloneables>>(x.arr)->Clone();
		else if (GetArray()->size() < x.GetArray()->size())GetArray()->Resize(x.GetArray()->size());
	}
	Random::Random(unsigned long long seed, size_t len) :arr(new LK::Collection::DefaultArray<u64>(len + 2 + (len + 17) / 8))
	{
		SetNextRand(seed);
	}
	Random::Random(const PULLArray  a) : arr(a) {}
	Random::Random(ptr<String> str)
	{
		index_t len = str->Length;
		LPCWSTR p = str;
		index_t k = (sizeof(WCHAR)*len+ sizeof(u64)-1) / sizeof(u64);
		index_t arrlen = k+1;
		arrlen += (arrlen + 7) / 8+1;
		if (arrlen < 5)arrlen = 5;
		arr = new Collection::DefaultArray<u64>(arrlen,(u64)0);
		u64* parr = GetArray();
		Memory::Copy(parr, p, sizeof(WCHAR)*len);
		parr[k++] = len;
		index_t mlen = (arrlen - 1) * 8 / 9;
		u8*pm = (u8*)(parr + mlen);
		for (k = 0; k < mlen; ++k)pm[k] = (k * len+0x5927f2) % 63 + 1;
		GetArray()->LastElement() = arrlen;
		if (len < 10)len = 10;
		for (index_t i = 0; i < len;++i)Rand();
	}
	void Random::SetNextRand(unsigned long long next)
	{
		u64* p = GetArray();
		index_t idx = GetArray()->size() - 1;
		index_t len = idx * 8 / 9;
		u8* pm = (u8*)(p + len);
		p[0] = 0x5c8173df2b96e40a;//这个数字是随意设置的
		pm[0] = next % 62 + 1;
		for (index_t i = 1; i < len; ++i)
		{
			p[i + 1] = (p[i] << 1) | ((s64)p[i] < 0);
			pm[i] = (Random::GetDefaultRef()->Rand() % 62) + 1;
			if (pm[i] == pm[i - 1])if (++pm[i] > 63)pm[i] = 1;
		}
		p[idx] = 0;
		p[(idx * 8 / 9) / 2] = next^p[0];
	}
	void Random::SetNextRandStatic(unsigned long long next)
	{
		u64* p = GetArray();
		index_t idx = GetArray()->size() - 1;
		index_t len = idx * 8 / 9;
		u8* pm = (u8*)(p + len);
		p[0] = 0x5c8173df2b96e40a;//这个数字是随意设置的
		pm[0] = next % 62 + 1;
		for (index_t i = 1; i < len; ++i)
		{
			p[i] = (p[i-1] << 1) | ((s64)p[i-1] < 0);
			pm[i] = (p[i - 1] % 62) + 1;
			if (pm[i] == pm[i - 1])if (++pm[i] > 63)pm[i] = 1;
		}
		p[idx] = 0;
		p[(idx * 8 / 9) / 2] = next^p[0];
	}
	unsigned long long Random::Rand()
	{
		index_t idx = GetArray()->size() - 1;
		index_t len = idx * 8 / 9;
		u64*p = GetArray();
		if ((index_t)++(p[idx]) >= len / 2)
		{
			p[idx] = 0;
			u8* pm = (u8*)(p + len);
			p[0] = ((p[0] << pm[0]) | (p[0] >> (64 - pm[0]))) + p[len - 1] + 1;
			for (index_t i = 1; i < len; ++i)p[i] = ((p[i] << pm[i]) | (p[i] >> (64 - pm[i]))) + p[i - 1] + 1;
		}
		return p[p[idx]] ^ p[p[idx] + len / 2];
	}
	unsigned long long Random::SecretRand()
	{
		GetArray()[0] ^= (u64)(10000000*Time::GetLocalSeconds()); return Rand();
	}
	Random::operator unsigned long long()const
	{
		return const_cast<Random*>(this)->Rand();
	}

	double Random::NextDouble()
	{
		return (Rand() >> 11) * (1.0 / 9007199254740992.0);
	}
	signed int Random::NextInt()
	{
		return 0x7fffffff & Rand();
	}
	signed short Random::NextShort()
	{
		return 0x7fff & Rand();
	}
	signed char Random::NextChar()
	{
		return 0x7f & Rand();
	}
	unsigned int Random::NextUInt()
	{
		return (unsigned int)Rand();
	}
	unsigned short Random::NextUShort()
	{
		return (unsigned short)Rand();
	}
	unsigned char Random::NextUChar()
	{
		return (unsigned char)Rand();
	}
	Mt64Random::Mt64Random() :Random(new LK::Collection::DefaultArray<u64>(313)) { SetNextRandStatic((u64)(10000000 * Time::GetLocalSeconds())); }
	Mt64Random::Mt64Random(u64 seed) { SetNextRandStatic(seed); }
	void Mt64Random::SetNextRand(u64 seed)
	{
		SetNextRandStatic(seed);
	}
	void Mt64Random::SetNextRandStatic(u64 seed)
	{
		u64* p = GetArray();
		p[312] = 0;
		p[0] = seed;
		for (int i = 1; i < 312; i++)
			p[i] = (6364136223846793005ull * (p[i - 1] ^ (p[i - 1] >> 62)) + i);
	}
	u64 Mt64Random::Rand()
	{
		u64* p = GetArray();
		if (p[312] >= 312) { p[312] = 0; Generate(); }
		u64 x = p[p[312]++];
		x ^= (x >> 29) & 0x5555555555555555ull;
		x ^= (x << 17) & 0x71D67FFFEDA60000ull;
		x ^= (x << 37) & 0xFFF7EEE000000000ull;
		return x ^ (x >> 43);
	}
	void Mt64Random::Generate()
	{
		u64* p = GetArray();
		index_t i;
		u64 x;
		for (i = 0; i < 156; i++) {
			x = (p[i] & 0xFFFFFFFF80000000ull) | (p[i + 1] & 0x7FFFFFFFull);
			if (x & 1)p[i] = p[i + 156] ^ (x >> 1) ^ 0xB5026F5AA96619E9ull;
			else p[i] = p[i + 156] ^ (x >> 1);
		}
		for (; i < 311; i++) {
			x = (p[i] & 0xFFFFFFFF80000000ull) | (p[i + 1] & 0x7FFFFFFFull);
			if (x & 1)p[i] = p[i - 156] ^ (x >> 1) ^ 0xB5026F5AA96619E9ull;
			else p[i] = p[i - 156] ^ (x >> 1);
		}
		x = (p[155] & 0xFFFFFFFF80000000ull) | (p[0] & 0x7FFFFFFFull);
		if (x & 1)p[311] = p[155] ^ (x >> 1) ^ 0xB5026F5AA96619E9ull;
		else p[311] = p[155] ^ (x >> 1);
	}
	//ptr<Random>
	ptr<Random>& Random::GetDefaultRef()
	{
		static ptr<Object>*p;
		if (p)return (ptr<Random>&)*p;
        Mutex::GetDefaultRef().Lock();
		if (!p)
		{
			static ptr<Object> obj = new Mt64Random();
			obj.UseCount.SetEnableThreadSafe(true);
			p = &obj;
		}
        Mutex::GetDefaultRef().UnLock();
		return (ptr<Random>&)*p;
	}

}
#endif
